package com.isyscore.os.core.util;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.isyscore.boot.login.LoginUserManager;
import com.isyscore.boot.login.properties.LoginProperties;
import com.isyscore.os.permission.common.constants.PermissionConstants;

import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author felixu
 * @since 2022.03.01
 */
public class InitiallyUtils {

    private static LoginProperties loginProperties;

    private static LoginUserManager loginUserManager;

    private static final ThreadLocal<Boolean> CONTAINS_INITIALLY = new ThreadLocal<>();

    private static void markInitially() {
        CONTAINS_INITIALLY.set(true);
    }

    public static boolean checkInitially() {
        return Optional.ofNullable(CONTAINS_INITIALLY.get()).orElse(false);
    }

    private static void  clear() {
        CONTAINS_INITIALLY.remove();
    }

    public static <T> T markInitially(Supplier<T> supplier) {
        markInitially();
        T result = supplier.get();
        clear();
        return result;
    }


    /**
     * 标记当下 DB 操作将在无租户拦截操作环境下执行，执行完成后清除标记，后续执行恢复正常
     *
     * @param supplier 需要执行的具体操作
     * @param <T> 返回的范性
     * @return 结果集
     */
    public static <T> T markIgnore(Supplier<T> supplier) {
        markInitially();
        T result = supplier.get();
        clear();
        return result;
    }

    public static <T, R> R withInitially(LambdaQueryWrapper<T> query, Function<LambdaQueryWrapper<T>, R> function, SFunction<T, ?> s) {
        // 获取 LoginUserManager 和 LoginProperties
        if (loginProperties == null)
            loginProperties = ApplicationUtils.getBean(LoginProperties.class);
        if (loginUserManager == null)
            loginUserManager = ApplicationUtils.getBean(LoginUserManager.class);
        // 校验是否需要被忽略拼接，交由租户拦截器处理
        if (!loginProperties.isEnable()
                || loginUserManager.isCurrentLoginUserSuperAdmin()
                || ignored())
            return function.apply(query);
        // 拼上当前租户和 initially 租户
        query.and(wrapper -> wrapper.eq(s, loginUserManager.getCurrentTenantId())
                .or()
                .eq(s, PermissionConstants.GLOBAL_BUSINESS_DATA_TENANT_ID_KEY));
        // 走忽略拼接，执行完整查询逻辑
        return markIgnore(() -> function.apply(query));
    }

    /**
     * 判断是否被打上了忽略标记，用户多租户拦截器的忽略逻辑判断
     *
     * @return 是否被忽略
     */
    public static boolean ignored() {
        return Optional.ofNullable(CONTAINS_INITIALLY.get()).orElse(false);
    }

}
